package levelrewind.android.app.model;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;

import levelrewind.android.app.R;
import levelrewind.android.app.model.Util.Emotion;
import levelrewind.android.app.vo.Game;
import levelrewind.android.app.vo.Person;
import levelrewind.android.app.vo.PicturePath;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.ImageView;

/**
 * Handler picture to display on application
 * 
 */
public class PictureHandler {

	private Context context;
	private final String FILE_TYPE = ".png"; 
	private final String DOWNLOAD_1PIC = "1Pic";
	private final String DOWNLOAD_ALLPIC = "AllPic";
	private final String POPAPP_PATH = "/popapp/";
//	private final String PERSON_PATH = "/person/";
	
	private String downloadType;
	private boolean isViewImage = false;
	private boolean isTaskCancel = false;
	private ImageView imageView;
	
	private Person person;
	private Game[] games;
	private Emotion displayEmotion;
	private AsyncTask<String, Void, ArrayList<Drawable>> downloadPictureTask;
	
	public PictureHandler(Context context){
		this.context = context;
		isViewImage = false;
		isTaskCancel = false;
	}
	
	/**
	 * Save picture to device on internal memory
	 * @param drawable
	 * @param fileName
	 */
	public void savePictureToDevice(Drawable drawable, String fileName) {	
		if (drawable == null) return;
		Bitmap bitmap = drawableToBitmap(drawable);
		FileOutputStream fos;
		try {
			fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
			bitmap.compress(CompressFormat.PNG, 90, fos); 
			Log.i(PictureHandler.class.getSimpleName(), "savePictureToDevice: "+ fileName);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} 	
	}
	
	/**
	 * Save picture to external memory. 
	 * Check if external memory is ready to use.
	 * @param drawable
	 * @param fileName
	 */
	public void savePictureToSDCard(Drawable drawable, String fileName) {	
		String state = Environment.getExternalStorageState(); 
		if (Environment.MEDIA_MOUNTED.equals(state)) { 
		    Log.i("SD CARD", "sdcard mounted and writable"); 
		    savePictureToSDCard(drawable, fileName, state);
		} 
		else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 
		    Log.i("SD CARD", "sdcard mounted readonly"); 
		    savePictureToDevice(drawable, fileName);
		} 
		else { 
		    Log.i("SD CARD", "sdcard state: " + state); 
		    savePictureToDevice(drawable, fileName);
		} 
	}
	
	/**
	 * Save picture to external memory on definition path
	 * @param drawable
	 * @param fileName
	 */
	private void savePictureToSDCard(Drawable drawable, String fileName, String state){
		//TODO: create sub directory, /person/
		//###NOTE: Vi gemmer ikke billederne i sd-card, fordi vi kan ikke få oprrette sub-direktory####//
		Bitmap bitmap = drawableToBitmap(drawable);
		ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 
		bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes); 
		    
		String root = Environment.getExternalStorageDirectory().toString();
		File dir = new File(root+ POPAPP_PATH);
		if (!dir.exists()) dir.mkdirs();

		File f = new File(root, POPAPP_PATH+fileName);
		FileOutputStream fo = null;
		try {
			fo = new FileOutputStream(f); 
			bitmap.compress(Bitmap.CompressFormat.PNG, 85, fo); 
			fo.flush();
			fo.close();
			Log.i(PictureHandler.class.getSimpleName(), "savePictureToSDCard:"+f.getAbsolutePath());
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * Read picture of the definite person and emotion
	 * @param person
	 * @param emotion
	 * @return
	 */
	public Drawable getPictureFromDevice(Person person, Emotion emotion) {
		 String fileName = getFileName(person, emotion);
		 Log.i(PictureHandler.class.getSimpleName(), "getPictureFromDevice: "+fileName);
		 File filePath = context.getFileStreamPath(fileName);
		 Drawable drawable = null;
		 if (filePath.exists()) { 
			 drawable = Drawable.createFromPath(filePath.toString());
		 } 
		 
		 return drawable;
	}
	
	public Drawable getPictureFromDevice(String fileName) {
		 Log.i(PictureHandler.class.getSimpleName(), "getPictureFromDevice: "+fileName);
		 File filePath = context.getFileStreamPath(fileName+FILE_TYPE);
		 Drawable drawable = null;
		 if (filePath.exists()) { 
			 drawable = Drawable.createFromPath(filePath.toString());
		 } 
		 
		 return drawable;
	}
	
	public Drawable readPictureFromSDCard(Person person, Emotion emotion) {
		Drawable drawable = null;
		String state = Environment.getExternalStorageState(); 
		if (Environment.MEDIA_MOUNTED.equals(state)) { 
		    Log.d("Test", "sdcard mounted and writable"); 
		    drawable = getPictureFromSDCard(person, emotion);
		} 
		else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 
		    Log.d("Test", "sdcard mounted readonly"); 
		    drawable = getPictureFromDevice(person, emotion);
		} 
		else { 
		    Log.d("Test", "sdcard state: " + state); 
		    drawable = getPictureFromDevice(person, emotion);
		} 
		
		return drawable;
	}
	
	private Drawable getPictureFromSDCard(Person person, Emotion emotion) {
		 String fileName = getFileName(person, emotion);
		 Drawable drawable = null;
		 String imageInSD = Environment.getExternalStorageDirectory().getAbsolutePath() +POPAPP_PATH+ fileName; 
		 Log.i(PictureHandler.class.getSimpleName(), "getImageFromSDCard: "+imageInSD);
	     Bitmap bitmap = BitmapFactory.decodeFile(imageInSD); 
	     if (bitmap != null) {
	    	 drawable = new BitmapDrawable(bitmap);
	     }

		 return drawable;
	}
	
	public void downloadAllPictureToDevice(Person person) {
		downloadType = DOWNLOAD_ALLPIC;
		this.person = person;
		if (person.getPicPath() != null) {
			PicturePath[] pp= (PicturePath[]) person.getPicPath().values().toArray();
			String[] paths = new String[pp.length];
			for (int i=0; i<pp.length;i++) paths[i] = pp[i].getPath();
			
			new DownloadPictureTask().execute(paths);
		}
	}
	
	public void downloadPictureToDevice(Person person, Emotion downloadEmotion) {
		String fileName = getFileName(person, downloadEmotion);
		if (isFileExists(fileName)) {
			viewImageFromDevice(context, person, downloadEmotion, imageView);
			return;
		}
		
		downloadType = DOWNLOAD_1PIC;
		this.person = person;
		this.displayEmotion = downloadEmotion;
		if (person.getPicPath() != null && person.getPicPath().size() != 0) {
			PicturePath pp = person.getPicPath().get(downloadEmotion);
			if (pp == null){
				pp = person.getPicPath().get(Emotion.NORMAL);
			}
			new DownloadPictureTask().execute(pp.getPath());
		}
	}
	
	public void downloadGamesIconsToDevice(Game[] games) {
		this.games = games;
		String[] paths = new String[games.length];
		for (int i=0; i<games.length;i++) paths[i] = games[i].getIconPath();
		
		new DownloadGamesIconsTask().execute(paths);
	}
	
	public static void viewImageFromDevice(Context c, Person p, Emotion emotion, ImageView iv) {
		PictureHandler ph = new PictureHandler(c);
		Drawable d = ph.getPictureFromDevice(p,  emotion);
		ph.setImageView(iv);
		ph.viewImage(d);
	}
	
	public static void downloadImageAndDisplay(Context c,Person p, Emotion emotion, ImageView iv) {
		PictureHandler ph = new PictureHandler(c);
		ph.setViewImage(true);
		ph.setImageView(iv);
		ph.downloadPictureToDevice(p, emotion);
		
	}
	
	public static void clearAllPictureFromDevice(Context context) {
		String[] allFiles = context.fileList(); 
		for(int k = 0 ; k < allFiles.length; k++) { 
		    context.deleteFile(allFiles[k]); 
		} 
		
		Log.i(PictureHandler.class.getSimpleName(), "Delete all pictures from internal memory.");
	}
	
	private boolean isFileExists(String fileName ) {
		File filePath = context.getFileStreamPath(fileName);
		if (filePath.exists()) return true;
		return false;
	}
		
	public void cancelTask() {
		if (downloadPictureTask != null) downloadPictureTask.cancel(true); 
		isTaskCancel = true;
		Log.i(this.getClass().getSimpleName(), "Clear all picture download tasks.");
	}
	
	private Bitmap drawableToBitmap (Drawable drawable) { 
	    if (drawable instanceof BitmapDrawable) { 
	        return ((BitmapDrawable)drawable).getBitmap(); 
	    } 
	 
	    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888); 
	    Canvas canvas = new Canvas(bitmap);  
	    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 
	    drawable.draw(canvas); 
	 
	    return bitmap; 
	}  
	
	public void viewImage(Drawable drawable) {
		if (isTaskCancel) return;
		
		//TODO: change default face image
		// Set to default face, if drawable is null
		if (drawable == null) imageView.setImageResource(R.drawable.face);
	    else imageView.setImageDrawable(drawable);
		
	}
	
	public String getFileName(Person person, Emotion emotion) {
		return person.getId()+emotion.name()+FILE_TYPE;
	}
	
	public boolean isViewImage() {
		
		return isViewImage;
	}

	public void setViewImage(boolean isViewImage) {
		this.isViewImage = isViewImage;
	}

	public Emotion getDisplayEmotion() {
		return displayEmotion;
	}

	public void setDisplayEmotion(Emotion displayEmotion) {
		this.displayEmotion = displayEmotion;
	}

	public ImageView getImageView() {
		return imageView;
	}

	public void setImageView(ImageView imageView) {
		this.imageView = imageView;
	}

	private class DownloadPictureTask extends AsyncTask<String, Void, ArrayList<Drawable>>
    {    	
		protected void onPostExecute(ArrayList<Drawable> drawables)
    	{	
			if (isCancelled()) return;
			
			if (drawables.size() == 0) return;
			
			if (downloadType == DOWNLOAD_1PIC) {
				savePictureToDevice(drawables.get(0), person.getId()+""+displayEmotion.name()+FILE_TYPE);
				if (isViewImage) viewImage(drawables.get(0));
			}
			else  {
				//Get key: NORMAL, HAPPY, SAD
				Map<Emotion, PicturePath> ppMap = person.getPicPath();
				Emotion[] keySet = (Emotion[])ppMap.keySet().toArray(); 
				
				// FileName = "personID""Emotion-name""FileType"
				for(int i=0; i<ppMap.size();i++) {
					savePictureToDevice(drawables.get(i), getFileName(person, keySet[i]));
					if (isViewImage) if (displayEmotion.name().equals(keySet[i].name())) viewImage(drawables.get(i));
				}
			}		
			
		}
    	
    	protected ArrayList<Drawable> doInBackground(String...params) {

			return downloadPicture(params); 

		}
    }
	
	private class DownloadGamesIconsTask extends AsyncTask<String, Void, ArrayList<Drawable>>
    {    	
		protected void onPostExecute(ArrayList<Drawable> drawables)
    	{	
			for (int i=0;i<drawables.size(); i++) {
				Drawable d = drawables.get(i);
				savePictureToDevice(d, games[i].getName()+FILE_TYPE);
			}
			
    	}
    	
    	protected ArrayList<Drawable> doInBackground(String...params) {

			return downloadPicture(params); 

		}
    }
	
	public ArrayList<Drawable> downloadPicture(String...params ){
		ArrayList<Drawable> list = new ArrayList<Drawable>();
		for (String address : params) {
			if (isTaskCancel) break;
    		Object content = null; 
		    try{ 
		      URL url = new URL(address); 
		      content = url.getContent(); 
		    } catch(Exception ex){ 
		        ex.printStackTrace();
		        Log.e(PictureHandler.class.getSimpleName(),ex.getMessage()+" : "+address);
		        return null;
		    } 

		    InputStream is = (InputStream)content; 
		    Drawable image = Drawable.createFromStream(is, "src");  
		    list.add(image);
		    Log.i(PictureHandler.class.getSimpleName(), "Download pictures: " +address);
    	}
		
		return list;
	}
	
}
